%ifndef BOOT_MEMORY_GETPHYSICALMEMORYINFO
%define BOOT_MEMORY_GETPHYSICALMEMORYINFO
%include "Boot/RealModeUtility/Print.asm"
%include "Boot/RealModeUtility/Halt.asm"
%include "Boot/RealModeUtility/ZeroMemory16.asm"
; 获取物理内存信息，存放到指定位置（实模式下使用）
; GetPhysicalMemoryInfo(void* pBuffer, unsigned DWORD dwCapacity)
; @param buffer 实模式下内存有效地址
; @param capacity 缓冲区容量

%define pBuffer [bp + 34]
%define dwCapacity [bp + 36]
bits 16
Boot.Memory.GetPhysicalMemoryInfo:
Boot.Memory.GetPhysicalMemoryInfo.Initialize:
    pushad
    mov bp, sp
    mov eax, 0xE820 ; 功能号
    xor ebx, ebx ; ebx 清零，BIOS 中断调用使用 ebx 保存 ARDS 编号
    ; 返回的 ARDS 存入 [es:di]
    mov cx, pBuffer ; ARDST 基址
    shr cx, 4 ; 右移 4 位得到段地址
    mov es, cx
    xor di, di
    mov ecx, ARDS_SIZE ; ARDS 大小
    mov edx, "PAMS" ; "SMAP" 字符串以纯 ASCII 码方式表示（即视作 128 进制数），小端字节序
Boot.Memory.GetPhysicalMemoryInfo.ClearBuffer: ; 将 ARDST 内容全部清零
    push word dwCapacity ; ARDST 大小
    push word pBuffer ; ARDST 基址
    call Boot.Memory.ZeroMemory16 ; ARDST 清零
    add sp, 2 * 2
Boot.Memory.GetPhysicalMemoryInfo.Get:
    int 0x15
    jc Boot.Memory.GetPhysicalMemoryInfo.Error ; 有进位表示错误
    add di, ARDS_SIZE ; 每个 ARDS 占 24 B，每返回一个 ARDS 就让 di 偏移 24 B
    cmp ebx, 0 ; 已返回所有 ARDS
    je Boot.Memory.GetPhysicalMemoryInfo.OK
    cmp di, dwCapacity ; 检查是否写满 ARDS 表
    je Boot.Memory.GetPhysicalMemoryInfo.OK
    mov eax, 0xE820 ; EAX will be set to "SMAP", so reset EAX to 0xe820 for next int
    jmp Boot.Memory.GetPhysicalMemoryInfo.Get
Boot.Memory.GetPhysicalMemoryInfo.Error:
    push word 0b0000_1100 ; 红色
    push word Boot.Memory.GetPhysicalMemoryInfo.ERROR_MSG
    push word 0
    call Boot.RealModeUtility.Print ; 打印字符串
    add sp, 2 * 3
    jmp Boot.RealModeUtility.Halt ; 停止运行
Boot.Memory.GetPhysicalMemoryInfo.OK:
    push word 0b0000_1010 ; 绿色
    push word Boot.Memory.GetPhysicalMemoryInfo.OK_MSG
    push word 0
    call Boot.RealModeUtility.Print ; 打印字符串
    add sp, 2 * 3
    jmp Boot.Memory.GetPhysicalMemoryInfo.Return ; 成功获取内存信息，返回
Boot.Memory.GetPhysicalMemoryInfo.Return:
    popad
    ret
Boot.Memory.GetPhysicalMemoryInfo.OK_MSG:
    db "[OK] Successfully get memory info.", 0x0d, 0x0a, 0x00
Boot.Memory.GetPhysicalMemoryInfo.ERROR_MSG:
    db "[ERROR] Failed to get physical memory info.", 0x0d, 0x0a, 0x00
%undef PARAM_BUFFER_OFFSET
%undef PARAM_CAPACITY_OFFSET
%endif